package model.player;

import java.util.LinkedList;
import java.util.List;

import model.map.GameMap;
import model.map.GameTile;
import model.mapping.PlayableMapping;
import model.playable.PlayableUser;
import model.playable.RallyPoint;
import model.playable.structure.Capital;
import model.playable.structure.Farm;
import model.playable.structure.Fort;
import model.playable.structure.Mine;
import model.playable.structure.ObservationTower;
import model.playable.structure.PowerPlant;
import model.playable.structure.Structure;
import model.playable.structure.University;
import model.playable.unit.Colonist;
import model.playable.unit.Explorer;
import model.playable.unit.Melee;
import model.playable.unit.Ranged;
import model.playable.unit.Unit;
import model.playable.unit.Vehicle;
import model.playable.unit.Worker;
import model.technology.PlayableTechnologyTree;
import model.visibility.PlayerView;
import model.visibility.VisibilityManager;

public class Player implements PlayableUser
{
	private GameTile startLoc;
	
	private ResourceManager resources;
	
	private VisibilityManager playerView;
	private ManagerCycler controllablePlayer;
	
	private RangedManager rangedUnits;
	private ColonistManager colonistUnits;
	private ExplorerManager explorerUnits;
	private MeleeManager meleeUnits;
	private VehicleManager vehicleUnits;
	
	private CapitalManager capitalStructures;
	private FarmManager farmStructures;
	private MineManager mineStructures;
	private PowerPlantManager powerplantStructures;
	private FortManager fortStructures;
	private UniversityManager universityStructures;
	private ObservationTowerManager towerStructures;
	
	private RallyPointManager rallyPoints;
	
	private int totalNumUnits, totalNumWorkers;
	private static final int MAX_NUM_OF_UNITS = 25, MAX_NUM_OF_WORKERS = 100;
	
	private List<String> walkableTerrains, vehicleTerrains;
	
	PlayableMapping mapping = PlayableMapping.getPlayableMapping();
	
	private PlayableTechnologyTree techTree;
	
	public Player(GameMap map, GameTile startLoc, List<String> walkableTerrains, List<String> vehicleTerrains)
	{
		this.walkableTerrains = walkableTerrains;
		this.vehicleTerrains = vehicleTerrains;
		
		this.startLoc = startLoc;
		
		resources = new ResourceManager();
		
		playerView = new VisibilityManager(map, this);
		
		rangedUnits = new RangedManager(this, resources, walkableTerrains);
		colonistUnits = new ColonistManager(this, resources, walkableTerrains);
		explorerUnits = new ExplorerManager(this, resources, walkableTerrains);
		explorerUnits.setVisibilityManager(playerView);
		
		meleeUnits = new MeleeManager(this, resources, walkableTerrains);
		vehicleUnits = new VehicleManager(this, resources, vehicleTerrains);
		
		capitalStructures = new CapitalManager(this, resources);
		farmStructures = new FarmManager(this, resources);
		mineStructures = new MineManager(this, resources);
		powerplantStructures = new PowerPlantManager(this, resources);
		fortStructures = new FortManager(this, resources);
		towerStructures = new ObservationTowerManager(this, resources);
		universityStructures = new UniversityManager(this, resources); // TODO EDIT
		
		rallyPoints = new RallyPointManager(this);
		
		totalNumUnits = totalNumWorkers = 0;
		
		controllablePlayer = new ManagerCycler();
		
		controllablePlayer.setRallyPointManager(rallyPoints);
		
		controllablePlayer.addUnitManager(colonistUnits);
		controllablePlayer.addUnitManager(explorerUnits);
		controllablePlayer.addUnitManager(meleeUnits);
		controllablePlayer.addUnitManager(rangedUnits);
		controllablePlayer.addUnitManager(vehicleUnits);
		
		controllablePlayer.addStructureManager(capitalStructures);
		controllablePlayer.addStructureManager(farmStructures);
		controllablePlayer.addStructureManager(mineStructures);
		controllablePlayer.addStructureManager(powerplantStructures);
		controllablePlayer.addStructureManager(fortStructures);
		controllablePlayer.addStructureManager(universityStructures);
		controllablePlayer.addStructureManager(towerStructures);
		
		//techTree = new PlayableTechnologyTree(colonistUnits, explorerUnits, rangedUnits, meleeUnits, capitalStructures, fortStructures, universityStructures, towerStructures, mineStructures, powerplantStructures, farmStructures);
		
		universityStructures.setTechTree(techTree);
		//   
		addColonist(startLoc);
		addExplorer(startLoc);
		addExplorer(startLoc);
		RallyPoint rp = rallyPoints.getRallyPoint(0);

		rp.addArmyUnit(colonistUnits.getUnit(0));
		rp.addArmyUnit(explorerUnits.getUnit(0));
		rp.addArmyUnit(explorerUnits.getUnit(1));
	}
	
	public PlayableTechnologyTree getTechTree()
	{
		return techTree;
	}
	
	public PlayerView getPlayerView()
	{
		return playerView;
	}
	
	public ControllablePlayer getControllablePlayer()
	{
		return controllablePlayer;
	}
	
	public boolean canAddUnits()
	{
		return totalNumUnits < MAX_NUM_OF_UNITS;
	}
	
	public boolean canAddWorkers()
	{
		return totalNumWorkers < MAX_NUM_OF_WORKERS;
	}
	
	public List<Worker> getNewWorkers(int num)
	{
		List<Worker> workers = new LinkedList<Worker>();
		
		for (int i = 0; i < num && totalNumWorkers < MAX_NUM_OF_WORKERS; i++)
		{
			workers.add(new Worker(this, walkableTerrains));
			totalNumWorkers++;
		}
		
		return workers;
	}
	
	@Override
	public void addRanged(GameTile tile)
	{
		if (!rangedUnits.isFull() && canAddUnits())
		{
			rangedUnits.createNewUnit(tile);
			totalNumUnits++;
		}
	}
	
	@Override
	public void addMelee(GameTile tile)
	{
		if (!meleeUnits.isFull() && canAddUnits())
		{
			meleeUnits.createNewUnit(tile);
			totalNumUnits++;
		}
	}
	
	@Override
	public void addColonist(GameTile tile)
	{
		if (!colonistUnits.isFull() && canAddUnits())
		{
			colonistUnits.createNewUnit(tile);
			totalNumUnits++;
		}
	}
	
	@Override
	public void addExplorer(GameTile tile)
	{
		if (!explorerUnits.isFull() && canAddUnits())
		{
			explorerUnits.createNewUnit(tile);
			totalNumUnits++;
		}
	}
	
	@Override
	public void addVehicle(GameTile tile)
	{
		if (!vehicleUnits.isFull() && canAddUnits())
		{
			vehicleUnits.createNewUnit(tile);
			totalNumUnits++;
		}
	}
	
	@Override
	public void addCapital(GameTile tile, Worker[] workers)
	{
		if (!capitalStructures.isFull())
		{
			capitalStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addFarm(GameTile tile, Worker[] workers)
	{
		if (!farmStructures.isFull())
		{
			farmStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addMine(GameTile tile, Worker[] workers)
	{
		if (!mineStructures.isFull())
		{
			mineStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addPowerPlant(GameTile tile, Worker[] workers)
	{
		if (!powerplantStructures.isFull())
		{
			powerplantStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addFort(GameTile tile, Worker[] workers)
	{
		if (!fortStructures.isFull())
		{
			fortStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addUniversity(GameTile tile, Worker[] workers)
	{
		if (!universityStructures.isFull())
		{
			universityStructures.createNewStructure(tile, workers);
		}
	}
	
	@Override
	public void addObservationTower(GameTile tile)
	{
		if (!towerStructures.isFull())
		{
			towerStructures.createNewStructure(tile, null);
		}
	}
	
	@Override
	public void addRallyPoint(GameTile tile, int num)
	{
		if (!rallyPoints.isFull())
		{
			rallyPoints.addRallyPoint(num, tile);
		}
	}
	
	public int getEnergyCount()
	{
		return resources.getEnergyAmount();
	}

	public int getFoodCount() {
		return resources.getFoodAmount();
	}

	public int getOreCount() {
		return resources.getOreAmount();
	}
	
	public void addFood(int amount)
	{
		resources.addFood(amount);
	}

	public void addOre(int amount)
	{
		resources.addOre(amount);
	}
	
	public void addEnergy(int amount)
	{
		resources.addEnergy(amount);
	}
	
	public void removeRanged(Ranged u)
	{
		rangedUnits.remove(u.getIdNumber());
	}
	
	public void removeColonist(Colonist u)
	{
		colonistUnits.remove(u.getIdNumber());
	}
	
	public void removeExplorer(Explorer u)
	{
		explorerUnits.remove(u.getIdNumber());
	}
	
	public void removeMelee(Melee u)
	{
		meleeUnits.remove(u.getIdNumber());
	}
	
	public void removeVehicle(Vehicle u)
	{
		rangedUnits.remove(u.getIdNumber());
	}
	
	public void removeCapital(Capital s)
	{
		capitalStructures.remove(s.getIdNumber());
	}
	
	public void removeFarm(Farm s)
	{
		farmStructures.remove(s.getIdNumber());
	}
	
	public void removeMine(Mine s)
	{
		mineStructures.remove(s.getIdNumber());
	}
	
	public void removePowerPlant(PowerPlant s)
	{
		powerplantStructures.remove(s.getIdNumber());
	}
	
	public void removeFort(Fort s)
	{
		fortStructures.remove(s.getIdNumber());
	}
	
	public void removeUniversity(University s)
	{
		universityStructures.remove(s.getIdNumber());
	}
	
	public void removeObservationTower(ObservationTower s)
	{
		towerStructures.remove(s.getIdNumber());
	}
	
	public List<Unit> getAllUnits()
	{
		List<Unit> units = new LinkedList<Unit>();
		
		units.addAll(rangedUnits.getAllUnits());
		units.addAll(meleeUnits.getAllUnits());
		units.addAll(explorerUnits.getAllUnits());
		units.addAll(colonistUnits.getAllUnits());
		
		return units;
	}

	public List<Vehicle> getAllVehicles()
	{
		List<Vehicle> vehicles = new LinkedList<Vehicle>();
		
		vehicles.addAll(vehicleUnits.getAllVehicles());
		
		return vehicles;
	}

	public List<Structure> getAllStructures()
	{
		List<Structure> structures = new LinkedList<Structure>();
		
		structures.addAll(capitalStructures.getAllStructures());
		structures.addAll(farmStructures.getAllStructures());
		structures.addAll(mineStructures.getAllStructures());
		structures.addAll(powerplantStructures.getAllStructures());
		structures.addAll(towerStructures.getAllStructures());
		structures.addAll(fortStructures.getAllStructures());
		structures.addAll(universityStructures.getAllStructures());
		
		
		return structures;
	}

	public void update()
	{
		rallyPoints.update();
		
		rangedUnits.update();
		colonistUnits.update();
		explorerUnits.update();
		meleeUnits.update();
		vehicleUnits.update();
		
		capitalStructures.update();
		farmStructures.update();
		mineStructures.update();
		powerplantStructures.update();
		fortStructures.update();
		universityStructures.update();
		towerStructures.update();
		
		mapping.update();
		
		playerView.update();
		
	}

	public GameTile getStartingLocation() 
	{
		return startLoc;
	}
}
